#if defined(MODBUS_TCP)|| defined(MODBUS_RTU)

/*
 * Copyright (c) 2002,2016 Mario de Sousa (msousa@fe.up.pt)
 *
 * This file is part of the Modbus library for Beremiz and matiec.
 *
 * This Modbus library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this Modbus library.  If not, see <http://www.gnu.org/licenses/>.
 *
 * This code is made available on the understanding that it will not be
 * used in safety-critical situations without a full and competent review.
 */

#include <fcntl.h> /* File control definitions */
#include <logger_rte.h>

#ifdef __linux__
#include <termio.h> /* POSIX terminal control definitions */
#endif

#include"plc_modbus.h"
#include "mb_layer1.h"
#include "mb_slave_private.h"
#include "mb_master_private.h"

//#define DEBUG 		/* uncomment to see the data sent and received */
#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

const layer1_funct_ptr_t fptr_[4] = {
#ifdef MODBUS_TCP
        {/* WARNING: TCP functions MUST be the first, as we have this hardcoded in the code! */
                /*          more specifically, in the get_ttyfd() macro in mb_slave.c               */
                /*                             in the mb_slave_new() function in mb_slave.c         */
                /*                             in the mb_master_connect() function in mb_master.c   */
                &modbus_tcp_write, &modbus_tcp_read, &modbus_tcp_init, &modbus_tcp_done, &modbus_tcp_connect,
                &modbus_tcp_listen, &modbus_tcp_close, &modbus_tcp_silence_init, &modbus_tcp_get_min_timeout},
#else
        {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
#endif
#ifdef MODBUS_RTU
        {&modbus_rtu_write, &modbus_rtu_read, &modbus_rtu_init, &modbus_rtu_done, &modbus_rtu_connect,
         &modbus_rtu_listen, &modbus_rtu_close, &modbus_rtu_silence_init, &modbus_rtu_get_min_timeout},
#else
        {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
#endif
#ifdef MODBUS_ASCII
        {&modbus_ascii_write, &modbus_ascii_read, &modbus_ascii_init, &modbus_ascii_done, &modbus_ascii_connect, &modbus_ascii_listen, &modbus_ascii_close, &modbus_ascii_silence_init, &modbus_ascii_get_min_timeout},
#else
        {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
#endif
        {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}};

/************************************************************************

	initialise / shutdown the library

	These functions sets up/shut down the library state
        (allocate memory for buffers, initialise data strcutures, etc)

**************************************************************************/
#define max(a, b) (((a) > (b)) ? (a) : (b))

int mb_slave_and_master_init(int nd_count_tcp, int nd_count_rtu, int nd_count_ascii) {
    int extra_bytes, extra_bytes_tcp = 0, extra_bytes_rtu = 0, extra_bytes_ascii = 0;

//    logger.debug("mb_slave_and_master_init creating %d nodes\n", nd_count_tcp);

/* initialise layer 1 library */
#ifdef MODBUS_TCP
    if (modbus_tcp_init(nd_count_tcp, DEF_OPTIMIZATION, &extra_bytes_tcp) < 0)
        goto error_exit_0;
#endif
#ifdef MODBUS_RTU
    if (modbus_rtu_init(nd_count_rtu, DEF_OPTIMIZATION, &extra_bytes_rtu) < 0)
        goto error_exit_1;
#endif
#ifdef MODBUS_ASCII
    if (modbus_ascii_init(nd_count_ascii, DEF_OPTIMIZATION, &extra_bytes_ascii) < 0)
      goto error_exit_2;
#endif
    extra_bytes = max(extra_bytes_tcp, extra_bytes_rtu);
    extra_bytes = max(extra_bytes, extra_bytes_ascii);

    /* initialise master and slave libraries... */
    if (mb_slave_init__(extra_bytes) < 0)
        goto error_exit_3;
    if (mb_master_init__(extra_bytes) < 0)
        goto error_exit_4;
    return 0;

/*
error_exit_3:
	modbus_master_done();
*/
    error_exit_4:
    mb_slave_done__();
    error_exit_3:
#ifdef MODBUS_ASCII
    modbus_ascii_done();
#endif
#ifdef MODBUS_RTU
    modbus_rtu_done();
#endif
    error_exit_1:
#ifdef MODBUS_TCP
    modbus_tcp_done();
#endif
    error_exit_0:
    return -1;
}

int mb_slave_and_master_done() {
    int res = 0;
    res |= mb_slave_done__();
    res |= mb_master_done__();
#ifdef MODBUS_ASCII
    res |= modbus_ascii_done();
#endif
#ifdef MODBUS_RTU
    res |= modbus_rtu_done();
#endif
#ifdef MODBUS_TCP
    res |= modbus_tcp_done();
#endif
    return res;
}
#endif